/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/

#include "kstructdata.h"
#include "kerror.h"
#include "kstream.h"
#include <string.h>

kStructDataBufferView::~kStructDataBufferView() {
	if (_data.ptr || _data.itemCount || _data.itemSize) {
		throw kError(_T("Invalid data buffer operation!"));
	}
}
kStructDataBuffer::kStructDataBuffer() {
}
kStructDataBuffer::kStructDataBuffer(size_t itemSize, size_t itemCount) {
	_data.itemSize = itemSize;
	resize(itemCount);
}
kStructDataBuffer::kStructDataBuffer(const kStructDataView& source) {
	replace(source);
}
kStructDataBuffer::kStructDataBuffer(size_t itemSize, kStream* stream) {
	size_t size = stream->getSize()/itemSize;

	_data.itemSize = itemSize;
	resize(size);
	stream->read(getStructData());
}
kStructDataBuffer::~kStructDataBuffer() {
	if (_data.ptr) {
		free(_data.ptr);
		_data.ptr = 0;
		_data.itemSize = 0;
		_data.itemCount = 0;
	}
}

void kStructDataBuffer::resize(size_t itemCount) {
	uint8_t* newptr = (uint8_t*)realloc(_data.ptr, itemCount*_data.itemSize);
	if (newptr || !itemCount || !_data.itemSize) {
		_data.itemCount = itemCount;
		_data.ptr = newptr;
	} else {
		throw kError(_T("Memory allocation failed!"));
	}
}
void kStructDataBuffer::fill(const uint8_t* value, size_t index, size_t count) const {
	if (index < _data.itemCount) {
		count = std::min(count, _data.itemCount - index);
		for (size_t i = index; i < index + count; i++)
			memcpy(_data.getItemPtr(i), value, _data.itemSize);
	}
}
void kStructDataBuffer::append(const kStructDataView& data) {
	if (data.itemSize != _data.itemSize)
		throw kError(_T("Cannot append kStructDataView with different item size!"));

	size_t oldsize = getSize();
	resize(_data.itemCount + data.itemCount);
	memcpy(_data.ptr + oldsize, data.ptr, data.getSize());
}
void kStructDataBuffer::replace(const kStructDataView& data) {
	resize(0);
	_data.itemSize = data.itemSize;
	resize(data.itemCount);
	memcpy(_data.ptr, data.ptr, data.getSize());
}
void kStructDataBuffer::replace(size_t itemSize, size_t itemCount) {
	resize(0);
	_data.itemSize = itemSize;
	resize(itemCount);
}
